{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "db68f9ed-b3d6-4722-92da-d23681ceaab2",
   "metadata": {},
   "source": [
    "# Exercise 2\n",
    "\n",
    "## Unsupervised Learning\n",
    "\n",
    "---\n",
    "\n",
    "## Overview\n",
    "\n",
    "Welcome to this excercise. We are now going to use our new skills to build our first unsupervised learning models. In particular, we are going to use multiple methods to create a number unsupervisoed learning models such kmeans for clustering and PCA to reduce the dimensionality of or data.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "3dcee46f-c65f-44e8-a60a-200a7c537219",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import os\n",
    "# Manually set the path relative to the py file's location that you want to import\n",
    "func_lib_path = os.path.abspath(os.path.join(os.getcwd(), '../../'))# Add the path to sys.path\n",
    "\n",
    "# Add the path to sys.path\n",
    "sys.path.append(func_lib_path)\n",
    "\n",
    "# Now you can import func_lib\n",
    "import func_lib\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.decomposition import PCA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "b6d8b3bc-ab25-4239-be50-b862780e10e9",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[*********************100%%**********************]  501 of 501 completed\n",
      "\n",
      "1 Failed download:\n",
      "['SW']: YFChartError(\"%ticker%: Data doesn't exist for startDate = 946702800, endDate = 1714536000\")\n"
     ]
    }
   ],
   "source": [
    "# Generate historical price data using the 'createHistPrices' function from 'func_lib'.\n",
    "# Assign the result to the variable 'historical_prices'.\n",
    "historical_prices = func_lib.create_hist_prices()\n",
    "\n",
    "# Define a list of momentum periods to be used in the computation.\n",
    "# Include periods such as 1, 2, 3, 29, 30, 31, 59, 60, and 61.\n",
    "list_of_momentums = [1, 2, 3, 29, 30, 31, 59, 60, 61]\n",
    "\n",
    "# Compute the returns using the 'computingReturns' function from 'func_lib'.\n",
    "# Pass 'historical_prices' and 'list_of_momentums' as arguments.\n",
    "# Assign the result to the variable 'total_returns'.\n",
    "total_returns = func_lib.compute_returns(historical_prices, list_of_momentums)\n",
    "\n",
    "# Drop the 'F_1_d_returns' column from the 'total_returns' DataFrame.\n",
    "# Use the 'drop()' method with 'columns' parameter and set 'inplace=True' to modify the DataFrame in place.\n",
    "total_returns.drop(columns={'F_1_d_returns'}, inplace=True)\n",
    "\n",
    "# Remove any rows with missing values from the 'total_returns' DataFrame.\n",
    "# Use the 'dropna()' method with 'inplace=True' to modify the DataFrame in place.\n",
    "total_returns.dropna(inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "76f45bce-e667-484a-bcb8-a87ea5557a45",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Standardize the features in the 'total_returns' DataFrame.\n",
    "# - Create a StandardScaler object.\n",
    "# - Use the 'fit_transform()' method of the scaler to standardize the features in 'total_returns'.\n",
    "# - Assign the standardized data to the variable 'X_scaled'.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "aaa15ab4-2ae5-4a95-9474-35f849b9baca",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize PCA (Principal Component Analysis).\n",
    "# - Create a PCA object to perform dimensionality reduction.\n",
    "\n",
    "\n",
    "\n",
    "# Fit PCA to the standardized data.\n",
    "# - Use the 'fit()' method of the PCA object to compute the principal components based on 'X_scaled'.\n",
    "\n",
    "\n",
    "# Transform the data to principal components.\n",
    "# - Use the 'transform()' method of the PCA object to project 'X_scaled' into the principal component space.\n",
    "# - Assign the transformed data to the variable 'X_pca'.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "00e1795a-f010-46be-9068-108cc0ae45e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Compute the explained variance ratio for each principal component.\n",
    "# - Use the 'explained_variance_ratio_' attribute of the PCA object to get the proportion of variance explained by each component.\n",
    "# - Assign the result to the variable 'explained_variance_ratio'.\n",
    "\n",
    "\n",
    "\n",
    "# Calculate the cumulative explained variance.\n",
    "# - Use 'np.cumsum()' to compute the cumulative sum of the explained variance ratios.\n",
    "# - Assign the result to the variable 'cumulative_explained_variance'.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "df092dd9-e0d8-4407-b0ad-5279a88a88a6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 47996 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the cumulative explained variance.\n",
    "# - Create a new figure with a specified size for the plot.\n",
    "# - Plot 'cumulative_explained_variance' against the number of principal components.\n",
    "# - Use markers and a dashed line style for better visualization.\n",
    "# - Add x-axis and y-axis labels, a title, and a grid to the plot.\n",
    "# - Display the plot using 'plt.show()'.\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(range(1, len(cumulative_explained_variance) + 1), cumulative_explained_variance, marker='o', linestyle='--')\n",
    "plt.xlabel('Number of Principal Components')\n",
    "plt.ylabel('Cumulative Explained Variance')\n",
    "plt.title('Cumulative Explained Variance by Principal Components')\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "a651fa11-7699-462c-9c6c-db45de1634fe",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "# Select the number of principal components that explain at least 90% of the variance.\n",
    "# - Use 'np.argmax()' to find the index of the first cumulative explained variance value that is greater than or equal to 0.90.\n",
    "# - Add 1 to the index because 'np.argmax()' returns a zero-based index.\n",
    "# - Assign the result to 'n_components' and print the value to display the number of components needed.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "3b667135-06da-4269-ad51-a774273e29a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Apply PCA with the selected number of components.\n",
    "# - Create a PCA object with 'n_components' set to the number of components that explain at least 90% of the variance.\n",
    "# - Fit the PCA object to the standardized data and transform it into the principal component space.\n",
    "# - Assign the transformed data to 'X_pca'.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "aeee24aa-c0b9-4655-8dcc-99ed0d71dd76",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                   PC1       PC2       PC3\n",
      "1_d_returns   0.133588  0.529824 -0.125951\n",
      "2_d_returns   0.171252  0.579465 -0.087760\n",
      "3_d_returns   0.188654  0.530649 -0.034944\n",
      "29_d_returns  0.391800 -0.048638  0.426830\n",
      "30_d_returns  0.395914 -0.056068  0.420983\n",
      "31_d_returns  0.396728 -0.063054  0.397994\n",
      "59_d_returns  0.388660 -0.174824 -0.379612\n",
      "60_d_returns  0.387706 -0.176128 -0.393599\n",
      "61_d_returns  0.384988 -0.175639 -0.397968\n"
     ]
    }
   ],
   "source": [
    "# Define the feature names.\n",
    "# - Extract the column names from the 'total_returns' DataFrame to use as feature names.\n",
    "# - Assign these column names to the variable 'features'.\n",
    "\n",
    "\n",
    "\n",
    "# Get the loadings of the principal components.\n",
    "# - Use the 'components_' attribute of the PCA object to get the principal component loadings.\n",
    "# - Assign the result to the variable 'loadings'.\n",
    "\n",
    "\n",
    "# Create a DataFrame of the loadings.\n",
    "# - Transpose the 'loadings' array using '.T' to match the features with the principal components.\n",
    "# - Use 'pd.DataFrame()' to create the DataFrame, setting the index to 'features' and the columns to principal component names.\n",
    "# - Assign the DataFrame to 'loadings_df'.\n",
    "\n",
    "\n",
    "# Display the loadings DataFrame.\n",
    "# - Use 'print()' to output the DataFrame to the console.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc380b77-2bbb-4773-a35b-66fbededb9ee",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
